home *** CD-ROM | disk | FTP | other *** search
/ Netscape Plug-Ins Developer's Kit / Netscape_Plug-Ins_Developers_Kit.iso / CGIPERL / MACPERL / MSRCE418.HQX / Perl Source ƒ / Perl / SubLaunch.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-11-13  |  9.6 KB  |  405 lines

  1. /*********************************************************************
  2. Project    :    SubLaunch        -    Call ToolServer
  3. File        :    SubLaunch.c        -    The code
  4. Author    :    Matthias Neeracher
  5. Started    :    06Dec91                                Language    :    MPW C/C++
  6. Modified    :    06Dec91    MN    
  7.                 07Mar92    MN    
  8.                 25Nov93    MN    Mo' better spin
  9. Last        :    25Nov93
  10.  
  11. Copyright (c) 1991, 1992 Matthias Neeracher
  12.  
  13.     You may distribute under the terms of the Perl Artistic License,
  14.     as specified in the README file.
  15.  
  16. *********************************************************************/
  17.  
  18. /* We need glue for Gestalt, but not for the rest of the stuff */
  19.  
  20. #include <GestaltEqu.h>
  21. #include "SubLaunch.h"
  22. #include "macperl.h"
  23. #include <TFileSpec.h>
  24. #include <GUSI.h>
  25.  
  26. #include <Types.h>
  27. #include <Processes.h>
  28. #include <Events.h>
  29. #include <AppleEvents.h>
  30. #include <CursorCtl.h>
  31. #include <Resources.h>
  32. #include <QuickDraw.h>
  33. #include <Folders.h>
  34. #include <Errors.h>
  35. #include <Script.h>
  36. #include <TextUtils.h>
  37.  
  38. #include <string.h>
  39.  
  40. #define FAILOSERR(call)    if (err = call)    return err
  41. #define ToolServer    'MPSX'
  42.  
  43. /* The following stuff is adapted from Jens Peter Alfke's SignatureToApp code */
  44.  
  45. static OSErr ToolServerRunning(ProcessSerialNumber *psn)
  46. {
  47.     OSErr err;
  48.     ProcessInfoRec info;
  49.     
  50.     psn->highLongOfPSN = 0;
  51.     psn->lowLongOfPSN  = kNoProcess;
  52.     do    {
  53.         FAILOSERR(GetNextProcess(psn));
  54.         info.processInfoLength     = sizeof(info);
  55.         info.processName             = nil;
  56.         info.processAppSpec         = nil;
  57.         FAILOSERR(GetProcessInformation(psn,&info));
  58.     } while(info.processSignature != ToolServer);
  59.  
  60.     *psn = info.processNumber;
  61.     
  62.     return noErr;
  63. }
  64.  
  65. static OSErr GetSysVolume(short *vRefNum)
  66. {
  67.     long dir;
  68.     
  69.     return FindFolder(kOnSystemDisk, kSystemFolderType, false, vRefNum, &dir);
  70. }
  71.  
  72.  
  73. static OSErr GetIndVolume(short index, short *vRefNum)
  74. {
  75.     OSErr             err;
  76.     ParamBlockRec     pb;
  77.     
  78.     pb.volumeParam.ioNamePtr     = nil;
  79.     pb.volumeParam.ioVolIndex     = index;
  80.     
  81.     FAILOSERR(PBGetVInfoSync(&pb));
  82.     
  83.     *vRefNum = pb.volumeParam.ioVRefNum;
  84.     
  85.     return noErr;
  86. }
  87.  
  88. static OSErr VolHasDesktopDB(short vRefNum, Boolean * hasDesktop)
  89. {
  90.     OSErr                         err;
  91.     HParamBlockRec             pb;
  92.     GetVolParmsInfoBuffer     info;
  93.     
  94.     pb.ioParam.ioNamePtr     = nil;
  95.     pb.ioParam.ioVRefNum     = vRefNum;
  96.     pb.ioParam.ioBuffer         = (Ptr)&info;
  97.     pb.ioParam.ioReqCount     = sizeof(GetVolParmsInfoBuffer);
  98.     
  99.     FAILOSERR(PBHGetVolParmsSync(&pb));
  100.  
  101.     *hasDesktop = (info.vMAttrib & (1 << bHasDesktopMgr))!=0;
  102.     
  103.     return noErr;
  104. }
  105.  
  106. static OSErr FindAppOnVolume(short vRefNum, FSSpec *file)
  107. {
  108.     OSErr     err;
  109.     DTPBRec     pb;
  110.     
  111.     /* Get Acess path to Desktop database on this volume */
  112.     
  113.     pb.ioVRefNum         = vRefNum;
  114.     pb.ioNamePtr         = nil;
  115.     FAILOSERR(PBDTGetPath(&pb));
  116.     
  117.     pb.ioIndex             = 0;
  118.     pb.ioFileCreator     = ToolServer;
  119.     pb.ioNamePtr         = file->name;
  120.     switch (err = PBDTGetAPPLSync(&pb))    {
  121.     case noErr:
  122.         file->vRefNum     = vRefNum;
  123.         file->parID     = pb.ioAPPLParID;
  124.     
  125.         return noErr;
  126.     case fnfErr:
  127.         return afpItemNotFound;                        /* Bug in PBDTGetAPPL            */
  128.     default:
  129.         return err;
  130.     }
  131. }
  132.  
  133. /* LaunchApplication in 32 bit everything environment    */
  134.  
  135. #if !defined(powerc) && !defined(__powerc)
  136. pascal OSErr WrappedLaunchApplication(const LaunchParamBlockRec *LaunchParams);
  137. #else
  138. #define WrappedLaunchApplication LaunchApplication
  139. #endif
  140.  
  141. static OSErr LaunchIt(const FSSpecPtr fileSpec, ProcessSerialNumber *psn )
  142. {
  143.     OSErr                     err;
  144.     LaunchParamBlockRec     pb;
  145.     
  146.     pb.launchBlockID             = extendedBlock;
  147.     pb.launchEPBLength         = extendedBlockLen;
  148.     pb.launchFileFlags         = launchNoFileFlags;
  149.     pb.launchControlFlags    = launchContinue | launchNoFileFlags | launchDontSwitch;
  150.     pb.launchAppSpec             = fileSpec;
  151.     pb.launchAppParameters    = nil;
  152.     
  153.     FAILOSERR(WrappedLaunchApplication(&pb));
  154.  
  155.     *psn = pb.launchProcessSN;
  156.     
  157.     return noErr;
  158. }
  159.  
  160. /* Get the psn of the ToolServer. Launch one if necessary. Buy one. Steal one. */
  161. static OSErr LaunchToolServer(ProcessSerialNumber *psn)
  162. {
  163.     OSErr     err;
  164.     short     sysVRefNum, vRefNum, index;
  165.     FSSpec     file;
  166.     Boolean     hasDesktopDB;
  167.     
  168.     /* See if ToolServer is already running:                    */
  169.     err    = ToolServerRunning(psn);
  170.     
  171.     if    (err != procNotFound)
  172.         return err;
  173.     
  174.     /* Not running, try to launch it */
  175.     
  176.     FAILOSERR(GetSysVolume(&sysVRefNum));
  177.     vRefNum     = sysVRefNum;
  178.     for (index = 0; !err; err = GetIndVolume(++index,&vRefNum)) {
  179.         if (!index || vRefNum != sysVRefNum) {
  180.             FAILOSERR(VolHasDesktopDB(vRefNum,&hasDesktopDB));
  181.             if (hasDesktopDB)    
  182.                 switch (err = FindAppOnVolume(vRefNum, &file))    {
  183.                 case noErr:
  184.                     return LaunchIt(&file,psn);
  185.                 case afpItemNotFound:
  186.                     break;
  187.                 default:
  188.                     return err;
  189.                 }
  190.         }
  191.     }
  192.     switch (err)    {
  193.     case nsvErr:
  194.     case afpItemNotFound:
  195.         return fnfErr;
  196.     default:
  197.         return err;
  198.     }
  199. }
  200.  
  201. typedef enum {
  202.     dontKnow,
  203.     canRun,
  204.     cantRun
  205. } featureCheck;
  206.  
  207. static featureCheck    requiredFeatures    =    dontKnow;
  208.  
  209. #define HASBIT(bit) (answer&(1<<bit))
  210. #define GESTALT(sel) !Gestalt(sel, &answer)
  211.  
  212. OSErr ValidateFeatures()
  213. {
  214.     long answer;
  215.     
  216.     switch (requiredFeatures)    {
  217.     case canRun:
  218.         return noErr;
  219.     case cantRun:
  220.         return gestaltUnknownErr;
  221.     case dontKnow:
  222.         if (    GESTALT(gestaltAppleEventsAttr)                            && 
  223.                     HASBIT(gestaltAppleEventsPresent)                     &&
  224.                  GESTALT(gestaltFindFolderAttr)                            &&
  225.                     HASBIT(gestaltFindFolderPresent)                     &&
  226.                 GESTALT(gestaltOSAttr)                                        &&
  227.                     HASBIT(gestaltLaunchCanReturn)                        &&
  228.                     HASBIT(gestaltLaunchFullFileSpec)                    &&
  229.                     HASBIT(gestaltLaunchControl)                            &&
  230.                 GESTALT(gestaltFSAttr)                                        &&
  231.                     HASBIT(gestaltHasFSSpecCalls)
  232.         )
  233.             requiredFeatures    =    canRun;
  234.         else
  235.             requiredFeatures     =     cantRun;
  236.         
  237.         return ValidateFeatures();
  238.     }
  239. }
  240.  
  241. #define FAILOSERR(call)    if (err = call)    return err
  242.  
  243. /* Create a temporary file in the temp folder. 
  244. */
  245. OSErr    FSpMakeTempFile(FSSpec * desc)
  246. {
  247.     static int    id    =    0;
  248.  
  249.     OSErr            err;
  250.     
  251.     FAILOSERR(FindFolder(kOnSystemDisk, 'temp', true, &desc->vRefNum, &desc->parID));
  252.     
  253.     *((long *) desc->name)        =    '\007tmp';
  254.     
  255.     do {
  256.         desc->name[4]    =    id / 1000     % 10 + '0';
  257.         desc->name[5]    =    id / 100        % 10 + '0';
  258.         desc->name[6]    =    id / 10        % 10 + '0';
  259.         desc->name[7]    =    id             % 10 + '0';
  260.         
  261.         ++id;
  262.         
  263.         err = HCreate(desc->vRefNum, desc->parID, desc->name, 'TEMP', 'TEXT');
  264.     } while (err == dupFNErr);
  265.     
  266.     return err;
  267. }
  268.             
  269. pascal Boolean SubLaunchIdle(EventRecord * ev, long * sleep, RgnHandle * rgn)
  270. {
  271.     SpinCursor(1);
  272.     
  273.     if (gHandleEvent)
  274.         (*gHandleEvent)(ev);
  275.     else if (ev->what == kHighLevelEvent)
  276.         if (AEProcessAppleEvent(ev)) 
  277.             return true;
  278.         
  279.     *sleep    =    10;
  280.     
  281.     return false;
  282. }
  283.  
  284. #if USESROUTINEDESCRIPTORS
  285. RoutineDescriptor    uSubLaunchIdle = 
  286.         BUILD_ROUTINE_DESCRIPTOR(uppAEIdleProcInfo, SubLaunchIdle);
  287. #else
  288. #define uSubLaunchIdle SubLaunchIdle
  289. #endif
  290.  
  291. static char * Fragments[] = {
  292.     "Directory \'",
  293.     "\'; Begin; ",
  294.     "; End<\'",
  295.     "\' >\'",
  296.     "\' │\'",
  297.     "\' ╖\'",
  298.     "\'\n",
  299.     "Dev:Null"
  300. };
  301.  
  302. #define BEGIN_TEXT        Fragments[0]
  303. #define DIRSET_TEXT        Fragments[1]
  304. #define END_TEXT            Fragments[2]
  305. #define STDOUT_TEXT        Fragments[3]
  306. #define STDERR_TEXT        Fragments[4]
  307. #define OUTERR_TEXT        Fragments[5]
  308. #define TERM_TEXT            Fragments[6]
  309. #define DEVNULL_TEXT        Fragments[7]
  310. #define DEVSTRING(dev)    (dev) ? FSp2FullPath(dev) : DEVNULL_TEXT
  311.         
  312. /* Execute the command. Any of the files may be set to NULL */
  313. OSErr SubLaunch(char * commandline, FSSpec * input, FSSpec * output, FSSpec * error, long * status)
  314. {
  315.     OSErr                        err;
  316.     Boolean                    same;
  317.     ProcessSerialNumber    psn;
  318.     ProcessSerialNumber    me;
  319.     AppleEvent                cmd;
  320.     AppleEvent                reply;
  321.     AEAddressDesc            addr;
  322.     acurHandle                acur;
  323.     Handle                    text;
  324.     char *                    segment;
  325.     FSSpec                    vol;
  326.     OSType                    type;
  327.     Size                        size;
  328.     
  329.     /* Check if the system is sexy enough */
  330.     FAILOSERR(ValidateFeatures());
  331.     
  332.     /* Get the psn of the ToolServer. Launch one if necessary. Buy one. Steal one. */
  333.     FAILOSERR(LaunchToolServer(&psn));
  334.     
  335.     /* It would be disastrous to send the event to ourselves (I know: I tried) */
  336.     FAILOSERR(GetCurrentProcess(&me));
  337.     FAILOSERR(SameProcess(&psn, &me, &same));
  338.     if (same)
  339.         return appMemFullErr;            /* This is a lie. So what ? */
  340.     
  341.     /* Build shell wrapper for command string */
  342.     FAILOSERR(PtrToHand(BEGIN_TEXT, &text, strlen(BEGIN_TEXT)));
  343.     FAILOSERR(Path2FSSpec(":", &vol));
  344.     segment    =    FSp2FullPath(&vol);
  345.     FAILOSERR(PtrAndHand(segment, text, strlen(segment)));
  346.     FAILOSERR(PtrAndHand(DIRSET_TEXT, text, strlen(DIRSET_TEXT)));
  347.     FAILOSERR(PtrAndHand(commandline, text, strlen(commandline)));
  348.     FAILOSERR(PtrAndHand(END_TEXT, text, strlen(END_TEXT)));
  349.     segment = DEVSTRING(input);
  350.     FAILOSERR(PtrAndHand(segment, text, strlen(segment)));
  351.     segment = DEVSTRING(output);
  352.     if (    output && error 
  353.         && output->vRefNum == error->vRefNum
  354.         && output->parID   == error->parID
  355.         && EqualString(output->name, error->name, false, true)
  356.     ) {
  357.         FAILOSERR(PtrAndHand(OUTERR_TEXT, text, strlen(OUTERR_TEXT)));
  358.         FAILOSERR(PtrAndHand(segment, text, strlen(segment)));
  359.     } else {
  360.         FAILOSERR(PtrAndHand(STDOUT_TEXT, text, strlen(STDOUT_TEXT)));
  361.         FAILOSERR(PtrAndHand(segment, text, strlen(segment)));
  362.         FAILOSERR(PtrAndHand(STDERR_TEXT, text, strlen(STDERR_TEXT)));
  363.         DEVSTRING(error);
  364.         FAILOSERR(PtrAndHand(segment, text, strlen(segment)));
  365.     }
  366.     FAILOSERR(PtrAndHand(TERM_TEXT, text, strlen(TERM_TEXT)));
  367.     
  368.     /* Build the AppleEvent */
  369.     FAILOSERR(
  370.         AECreateDesc(typeProcessSerialNumber, (Ptr) &psn, sizeof(psn), &addr));
  371.     FAILOSERR(
  372.         AECreateAppleEvent('misc', 'dosc', &addr, 
  373.             kAutoGenerateReturnID, kAnyTransactionID, 
  374.             &cmd));
  375.     HLock(text);
  376.     FAILOSERR(
  377.         AEPutParamPtr(&cmd, '----', typeChar, *text, GetHandleSize(text)));
  378.     DisposHandle(text);
  379.     
  380.     /* Send it */
  381.     acur    =    (acurHandle) GetResource('acur', 128);
  382.     DetachResource((Handle) acur);
  383.     InitCursorCtl(acur);
  384.     err    =    
  385.         AESend(
  386.             &cmd, &reply, kAEWaitReply+kAENeverInteract, 
  387.             kAENormalPriority, kNoTimeOut, 
  388.             (AEIdleUPP) &uSubLaunchIdle, nil);
  389.         
  390.     if (AEGetParamPtr(&reply, 'stat', typeLongInteger, &type, (Ptr) status, 4, &size))
  391.         *status = 0;
  392.         
  393.     AEDisposeDesc(&cmd);
  394.     AEDisposeDesc(&addr);
  395.     AEDisposeDesc(&reply);
  396.     
  397.     ReleaseResource((Handle) acur);
  398.     
  399.     InitCursorCtl(NULL);
  400.     
  401.     return err;
  402. }
  403.  
  404.  
  405.